package com.huangkailong.gitimgbed.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.google.inject.Inject;
import com.huangkailong.gitimgbed.core.ImgBedConfiguration;
import com.huangkailong.gitimgbed.jgit.Jgit;
import com.huangkailong.gitimgbed.core.SystemException;
import com.huangkailong.gitimgbed.service.JgitService;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;

import java.io.File;
import java.io.IOException;

/**
 * @author huangkl
 * @since 1.0.0
 */
@Slf4j
public class JgitServiceImpl implements JgitService {
    private final ImgBedConfiguration setting;
    private Jgit jgit;
    private boolean gitRepositoryInitFlag = false;

    @Inject
    public JgitServiceImpl(ImgBedConfiguration setting) {
        this.setting = setting;
    }

    private Jgit buildJgit() {
        final String gitUsername = setting.getGitUsername();
        final String gitPasswd = setting.getGitPasswd();
        final Jgit.Builder builder = new Jgit.Builder();
        final String gitRepositoryLocalPath = setting.getGitRepositoryLocalPath();
        builder.setUrl(setting.getGitRepositoryUrl())
                .setBranch(setting.getGitRepositoryBranch());
        if(StrUtil.isBlank(gitRepositoryLocalPath)){
            builder.setLocalPath(System.getProperty("java.io.tmpdir"));
        }
        if(StrUtil.isNotBlank(gitUsername) && StrUtil.isNotBlank(gitPasswd)){
            final UsernamePasswordCredentialsProvider credentialsProvider =
                    new UsernamePasswordCredentialsProvider(setting.getGitUsername(), setting.getGitPasswd());
            builder.setCredentialsProvider(credentialsProvider);
        }
        return builder.build();
    }

    private void doInitRepository(Jgit jgit) {
        try {
            final File repositoryPath = jgit.getRepositoryPath();
            if(!repositoryPath.exists()){
                jgit.cloneRepository();
            }else if(!this.jgit.exits()){
                FileUtil.del(repositoryPath);
                jgit.cloneRepository();
            }else {
                jgit.pull();
            }
        } catch (GitAPIException | IOException e) {
            log.error(e.getMessage(), e);
            throw new SystemException(e.getMessage(), e);
        }
    }

    private String getFileNewName(File f) {
        final String suffix = FileUtil.getSuffix(f.getName());
        return IdUtil.simpleUUID()+"."+suffix;
    }

    /**
     * 初始化 git 仓库
     */
    public void initGitRepository(){
        log.info("开始初始化 git 仓库");
        final long start = System.currentTimeMillis();
        this.jgit = buildJgit();
        doInitRepository(this.jgit);
        this.gitRepositoryInitFlag = true;
        log.info("git 仓库初始化完成，耗时："+(System.currentTimeMillis()-start)+" ms");
    }

    @Override
    public String addFile2RemoteRepository(File file) throws Exception {
        Assert.notNull(file, "file 不能为 null!");
        if(!this.gitRepositoryInitFlag){
            initGitRepository();
        }

        final String newName = getFileNewName(file);
        final String repositoryPath = jgit.getRepositoryPath().getAbsolutePath();
        final File dest = new File(repositoryPath, newName);
        FileUtil.copy(file, dest, true);
        jgit.executeCommands((git, jgit)->{
            git.add().addFilepattern(".").call();
            git.commit().setMessage("提交 "+newName).call();
            final PushCommand push = git.push();
            jgit.setAuth(push);
            final Iterable<PushResult> pushResults = push.call();
            pushResults.forEach(pushResult -> log.debug(pushResult.getMessages()));
        });
        return setting.getImgUrlPrefix()+newName;
    }

    @Override
    public void flushJgitConfig() {
        this.gitRepositoryInitFlag = false;
        this.jgit = null;
    }
}
